package org.infodavid.common.scheduler.impl;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.infodavid.common.lang.ClassUtil;
import org.infodavid.common.scheduler.commands.IScheduledCommand;
import org.infodavid.common.scheduler.exceptions.SchedulerExecutionException;
import org.infodavid.common.util.IVisitor;

/**
 * The Class SchedulerJob.
 */
public class SchedulerJob {
  /** The Constant log. */
  private static final Log LOGGER = LogFactory.getLog(SchedulerJob.class);

  /**
   * See super class or interface. (non-Javadoc)
   * @see org.quartz.Job#execute(org.quartz.JobExecutionContext)
   */
  @SuppressWarnings({
      "rawtypes", "unchecked"
  })
  public void execute(final JobExecutionContext context) throws JobExecutionException {
    final boolean isDebugEnabled = LOGGER.isDebugEnabled();
    final long startTime = System.currentTimeMillis();

    if (isDebugEnabled) {
      LOGGER.debug("Executing job using context: " + toString(context));
    }

    JobDetail jobDetail;
    IScheduledCommand cmd;

    try {
      jobDetail = context.getJobDetail();
      cmd = (IScheduledCommand)jobDetail.getJobDataMap().get(SchedulerServiceImpl.COMMAND_KEY);
    }
    catch (final Exception e) {
      cmd = null;
      jobDetail = null;

      if (isDebugEnabled) {
        LOGGER.debug("An invalid job was passed to the scheduler: " + context.getJobDetail(), e);
      }

      LOGGER.warn("An invalid job was passed to the scheduler: " + context.getJobDetail());
    }

    if (jobDetail == null || cmd == null) {
      LOGGER.warn("An invalid command was passed to the scheduler: " + context.getJobDetail());
    }
    else {
      if (cmd.getExpirationDate() != null && cmd.getExpirationDate().isBeforeNow()) {
        LOGGER.warn("Command expired: " + context.getJobDetail());

        context.setResult(IVisitor.FAILURE);
        context.setJobRunTime(System.currentTimeMillis() - startTime);
      }
      else {
        try {
          final IVisitor visitor = ClassUtil.getInstance().newInstance(cmd.getProcessorClass());
          IVisitor.IResult result = visitor.visit(cmd);

          context.setResult(result);
          context.setJobRunTime(System.currentTimeMillis() - startTime);
        }
        catch (final Throwable e) {
          if (isDebugEnabled) {
            LOGGER.debug("An error occurs while executing task: " + cmd, e);
          }

          context.setResult(e);

          throw new SchedulerExecutionException(e, true);
        }
      }
    }
  }

  /**
   * To string.
   * @param context the context
   * @return the string
   */
  private String toString(final JobExecutionContext context) {
    final StringBuffer buffer = new StringBuffer();

    buffer.append(super.toString());
    buffer.append("[fireTime = ");
    buffer.append(context.getFireTime());
    buffer.append(", refireCount = ");
    buffer.append(context.getRefireCount());
    buffer.append(']');

    return buffer.toString();
  }
}
